use std::net::IpAddr;

use crate::domain::vo::{CpuVO, DiskVO, Memory, ServerVO, SysVO};
use bytesize::ByteSize;
use sysinfo::{CpuExt, DiskExt, NetworkExt, System, SystemExt};

pub fn get_server_info() -> ServerVO {
    let mut sys = System::new_all();

    // First we update all information of our `System` struct.
    sys.refresh_all();

    // We display all disks' information:
    // println!("=> disks:");
    let mut sys_file = vec![];
    for d in sys.disks() {
        let disk = DiskVO {
            dir_name: d.name().to_str().unwrap().to_string(),
            free: ByteSize::b(d.available_space()).to_string(),
            sys_type_name: String::from_utf8(d.file_system().to_vec()).unwrap(),
            type_name: d.mount_point().to_str().unwrap().to_string(),
            total: ByteSize::b(d.total_space()).to_string(),
            used: ByteSize::b(d.total_space() - d.available_space()).to_string(),
            usage: format!(
                "{:.1}",
                100.0
                    - 100.0 * (d.total_space() - d.available_space()) as f64
                        / d.total_space() as f64
            ),
        };
        sys_file.push(disk);
        //     println!("{:?}", disk);
        //   println!("{:?}", disk_);
    }

    // Network interfaces name, data received and data transmitted:
    //   println!("=> networks:");
    for (interface_name, data) in sys.networks() {
        println!(
            "{}: {}/{} B",
            interface_name,
            data.received(),
            data.transmitted()
        );
    }

    // Components temperature:
    println!("=> components:");
    for component in sys.components() {
        println!("{:?}", component);
    }

    let mem = Memory {
        free: ByteSize::b(sys.used_memory())
            .to_string()
            .trim_end_matches(" GB")
            .to_string(), //fixme .trim_end_matches(" GB").to_string()为了兼容前端，以后需要删除
        total: ByteSize::b(sys.total_memory())
            .to_string()
            .trim_end_matches(" GB")
            .to_string(),
        used: ByteSize::b(sys.total_memory() - sys.used_memory())
            .to_string()
            .trim_end_matches(" GB")
            .to_string(),
        usage: format!(
            "{:.1}",
            100.0 - 100.0 * sys.used_memory() as f64 / sys.total_memory() as f64
        ),
    };
    // println!("{:?}", mem);
    sys.refresh_cpu();
    let cpu_usage = sys.global_cpu_info().cpu_usage();
    let cpu = CpuVO {
        cpu_num: sys.physical_core_count().unwrap() as u8,
        free: 100.0 - cpu_usage,
        sys: 0.0,
        total: 0,
        used: cpu_usage,
        wait: 0.0,
    };

    let mut ip_str = "127.0.0.1".to_string();
    let ip_res = get_local_ip();
    match ip_res {
        Ok(ip) => {
            ip_str = ip.to_string();
        },
        Err(err) => {
            println!("IP acquisition exception {}", err);
        }
    }

    // println!("{:?}", cpu);
    let sys_vo = SysVO {
        computer_ip: ip_str,
        computer_name: sys.host_name().unwrap(),
        os_arch: std::env::consts::ARCH.to_string(),
        os_name: format!("{} {}", sys.name().unwrap(), sys.os_version().unwrap()),
    };
    // println!("{:?}", sys_vo);
    ServerVO {
        cpu,
        mem,
        sys: sys_vo,
        sys_files: sys_file,
    }
}

// 获取服务器IP
fn get_local_ip() -> Result<IpAddr, Box<dyn std::error::Error>> {
    // 使用网络库来获取本机的IP地址
    let socket = std::net::UdpSocket::bind("0.0.0.0:0")?;
    socket.connect("8.8.8.8:80")?;
    let local_ip = socket.local_addr()?.ip();
    Ok(local_ip)
}